{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Configurations for Colab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "IN_COLAB = \"google.colab\" in sys.modules\n",
    "\n",
    "if IN_COLAB:\n",
    "    !apt install python-opengl\n",
    "    !apt install ffmpeg\n",
    "    !apt install xvfb\n",
    "    !pip install pyvirtualdisplay\n",
    "    !pip install gym[all]\n",
    "    from pyvirtualdisplay import Display\n",
    "    \n",
    "    # Start virtual display\n",
    "    dis = Display(visible=0, size=(400, 400))\n",
    "    dis.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 07. N-Step Learning\n",
    "\n",
    "[R. S. Sutton, \"Learning to predict by the methods of temporal differences.\" Machine learning, 3(1):9–44, 1988.](http://incompleteideas.net/papers/sutton-88-with-erratum.pdf)\n",
    "\n",
    "Q-learning accumulates a single reward and then uses the greedy action at the next step to bootstrap. Alternatively, forward-view multi-step targets can be used (Sutton 1988). We call it Truncated N-Step Return\n",
    "from a given state $S_t$. It is defined as,\n",
    "\n",
    "$$\n",
    "R^{(n)}_t = \\sum_{k=0}^{n-1} \\gamma_t^{(k)} R_{t+k+1}.\n",
    "$$\n",
    "\n",
    "A multi-step variant of DQN is then defined by minimizing the alternative loss,\n",
    "\n",
    "$$\n",
    "(R^{(n)}_t + \\gamma^{(n)}_t \\max_{a'} q_{\\theta}^{-}\n",
    "(S_{t+n}, a')\n",
    "- q_{\\theta}(S_t, A_t))^2.\n",
    "$$\n",
    "\n",
    "Multi-step targets with suitably tuned $n$ often lead to faster learning (Sutton and Barto 1998)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from collections import deque\n",
    "from typing import Deque, Dict, List, Tuple\n",
    "\n",
    "import gym\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "from IPython.display import clear_output"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Replay buffer for N-step learning\n",
    "\n",
    "There are a little bit changes in Replay buffer for N-step learning. First, we use `deque` to store the most recent n-step transitions.\n",
    "\n",
    "```python\n",
    "    self.n_step_buffer = deque(maxlen=n_step)\n",
    "```\n",
    "\n",
    "You can see it doesn't actually store a transition in the buffer, unless `n_step_buffer` is full.\n",
    "\n",
    "```\n",
    "    # in store method\n",
    "    if len(self.n_step_buffer) < self.n_step:\n",
    "        return ()\n",
    "```\n",
    "\n",
    "When the length of `n_step_buffer` becomes equal to N, it eventually stores the N-step transition, which is calculated by `_get_n_step_info` method.\n",
    "\n",
    "(Please see *01.dqn.ipynb* for detailed description of the basic replay buffer.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReplayBuffer:\n",
    "    \"\"\"A simple numpy replay buffer.\"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        obs_dim: int, \n",
    "        size: int, \n",
    "        batch_size: int = 32, \n",
    "        n_step: int = 3, \n",
    "        gamma: float = 0.99,\n",
    "    ):\n",
    "        self.obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.next_obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.acts_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.rews_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.done_buf = np.zeros(size, dtype=np.float32)\n",
    "        self.max_size, self.batch_size = size, batch_size\n",
    "        self.ptr, self.size, = 0, 0\n",
    "        \n",
    "        # for N-step Learning\n",
    "        self.n_step_buffer = deque(maxlen=n_step)\n",
    "        self.n_step = n_step\n",
    "        self.gamma = gamma\n",
    "\n",
    "    def store(\n",
    "        self, \n",
    "        obs: np.ndarray, \n",
    "        act: np.ndarray, \n",
    "        rew: float, \n",
    "        next_obs: np.ndarray, \n",
    "        done: bool\n",
    "    ) -> Tuple[np.ndarray, np.ndarray, float, np.ndarray, bool]:\n",
    "        transition = (obs, act, rew, next_obs, done)\n",
    "        self.n_step_buffer.append(transition)\n",
    "\n",
    "        # single step transition is not ready\n",
    "        if len(self.n_step_buffer) < self.n_step:\n",
    "            return ()\n",
    "        \n",
    "        # make a n-step transition\n",
    "        rew, next_obs, done = self._get_n_step_info(\n",
    "            self.n_step_buffer, self.gamma\n",
    "        )\n",
    "        obs, act = self.n_step_buffer[0][:2]\n",
    "        \n",
    "        self.obs_buf[self.ptr] = obs\n",
    "        self.next_obs_buf[self.ptr] = next_obs\n",
    "        self.acts_buf[self.ptr] = act\n",
    "        self.rews_buf[self.ptr] = rew\n",
    "        self.done_buf[self.ptr] = done\n",
    "        self.ptr = (self.ptr + 1) % self.max_size\n",
    "        self.size = min(self.size + 1, self.max_size)\n",
    "        \n",
    "        return self.n_step_buffer[0]\n",
    "\n",
    "    def sample_batch(self) -> Dict[str, np.ndarray]:\n",
    "        indices = np.random.choice(\n",
    "            self.size, size=self.batch_size, replace=False\n",
    "        )\n",
    "\n",
    "        return dict(\n",
    "            obs=self.obs_buf[indices],\n",
    "            next_obs=self.next_obs_buf[indices],\n",
    "            acts=self.acts_buf[indices],\n",
    "            rews=self.rews_buf[indices],\n",
    "            done=self.done_buf[indices],\n",
    "            # for N-step Learning\n",
    "            indices=indices,\n",
    "        )\n",
    "    \n",
    "    def sample_batch_from_idxs(\n",
    "        self, indices: np.ndarray\n",
    "    ) -> Dict[str, np.ndarray]:\n",
    "        # for N-step Learning\n",
    "        return dict(\n",
    "            obs=self.obs_buf[indices],\n",
    "            next_obs=self.next_obs_buf[indices],\n",
    "            acts=self.acts_buf[indices],\n",
    "            rews=self.rews_buf[indices],\n",
    "            done=self.done_buf[indices],\n",
    "        )\n",
    "    \n",
    "    def _get_n_step_info(\n",
    "        self, n_step_buffer: Deque, gamma: float\n",
    "    ) -> Tuple[np.int64, np.ndarray, bool]:\n",
    "        \"\"\"Return n step rew, next_obs, and done.\"\"\"\n",
    "        # info of the last transition\n",
    "        rew, next_obs, done = n_step_buffer[-1][-3:]\n",
    "\n",
    "        for transition in reversed(list(n_step_buffer)[:-1]):\n",
    "            r, n_o, d = transition[-3:]\n",
    "\n",
    "            rew = r + gamma * rew * (1 - d)\n",
    "            next_obs, done = (n_o, d) if d else (next_obs, done)\n",
    "\n",
    "        return rew, next_obs, done\n",
    "\n",
    "    def __len__(self) -> int:\n",
    "        return self.size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Network\n",
    "\n",
    "We are going to use a simple network architecture with three fully connected layers and two non-linearity functions (ReLU)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Network(nn.Module):\n",
    "    def __init__(self, in_dim: int, out_dim: int):\n",
    "        \"\"\"Initialization.\"\"\"\n",
    "        super(Network, self).__init__()\n",
    "\n",
    "        self.layers = nn.Sequential(\n",
    "            nn.Linear(in_dim, 128), \n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, 128), \n",
    "            nn.ReLU(), \n",
    "            nn.Linear(128, out_dim)\n",
    "        )\n",
    "\n",
    "    def forward(self, x: torch.Tensor) -> torch.Tensor:\n",
    "        \"\"\"Forward method implementation.\"\"\"\n",
    "        return self.layers(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DQN Agent + N-step learning Agent\n",
    "\n",
    "Here is a summary of DQNAgent class.\n",
    "\n",
    "| Method           | Note                                                 |\n",
    "| ---              | ---                                                  |\n",
    "|select_action     | select an action from the input state.               |\n",
    "|step              | take an action and return the response of the env.   |\n",
    "|compute_dqn_loss  | return dqn loss.                                     |\n",
    "|update_model      | update the model by gradient descent.                |\n",
    "|target_hard_update| hard update from the local model to the target model.|\n",
    "|train             | train the agent during num_frames.                   |\n",
    "|test              | test the agent (1 episode).                          |\n",
    "|plot              | plot the training progresses.                        |\n",
    "\n",
    "We use two buffers: `memory` and `memory_n` for 1-step transitions and n-step transitions respectively. It guarantees that any paired 1-step and n-step transitions have the same indices (See `step` method for more details). Due to the reason, we can sample pairs of transitions from the two buffers once we have indices for samples.\n",
    "\n",
    "```python\n",
    "    def update_model(self) -> torch.Tensor:\n",
    "        ...\n",
    "        samples = self.memory.sample_batch()\n",
    "        indices = samples[\"indices\"]\n",
    "        ...\n",
    "        \n",
    "        # N-step Learning loss\n",
    "        if self.use_n_step:\n",
    "            samples = self.memory_n.sample_batch_from_idxs(indices)\n",
    "            ...\n",
    "```\n",
    "\n",
    "One thing to note that  we are gonna combine 1-step loss and n-step loss so as to control high-variance / high-bias trade-off.\n",
    "\n",
    "(Search the comments with *N-step Leaning* to see any difference from DQN.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DQNAgent:\n",
    "    \"\"\"DQN Agent interacting with environment.\n",
    "    \n",
    "    Attribute:\n",
    "        env (gym.Env): openAI Gym environment\n",
    "        memory (ReplayBuffer): replay memory to store transitions\n",
    "        batch_size (int): batch size for sampling\n",
    "        epsilon (float): parameter for epsilon greedy policy\n",
    "        epsilon_decay (float): step size to decrease epsilon\n",
    "        max_epsilon (float): max value of epsilon\n",
    "        min_epsilon (float): min value of epsilon\n",
    "        target_update (int): period for target model's hard update\n",
    "        gamma (float): discount factor\n",
    "        dqn (Network): model to train and select actions\n",
    "        dqn_target (Network): target model to update\n",
    "        optimizer (torch.optim): optimizer for training dqn\n",
    "        transition (list): transition information including \n",
    "                           state, action, reward, next_state, done\n",
    "        use_n_step (bool): whether to use n_step memory\n",
    "        n_step (int): step number to calculate n-step td error\n",
    "        memory_n (ReplayBuffer): n-step replay buffer\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        env: gym.Env,\n",
    "        memory_size: int,\n",
    "        batch_size: int,\n",
    "        target_update: int,\n",
    "        epsilon_decay: float,\n",
    "        max_epsilon: float = 1.0,\n",
    "        min_epsilon: float = 0.1,\n",
    "        gamma: float = 0.99,\n",
    "        # N-step Learning\n",
    "        n_step: int = 3,\n",
    "    ):\n",
    "        \"\"\"Initialization.\n",
    "        \n",
    "        Args:\n",
    "            env (gym.Env): openAI Gym environment\n",
    "            memory_size (int): length of memory\n",
    "            batch_size (int): batch size for sampling\n",
    "            target_update (int): period for target model's hard update\n",
    "            epsilon_decay (float): step size to decrease epsilon\n",
    "            lr (float): learning rate\n",
    "            max_epsilon (float): max value of epsilon\n",
    "            min_epsilon (float): min value of epsilon\n",
    "            gamma (float): discount factor\n",
    "            n_step (int): step number to calculate n-step td error\n",
    "        \"\"\"\n",
    "        obs_dim = env.observation_space.shape[0]\n",
    "        action_dim = env.action_space.n\n",
    "        \n",
    "        self.env = env\n",
    "        self.batch_size = batch_size\n",
    "        self.epsilon = max_epsilon\n",
    "        self.epsilon_decay = epsilon_decay\n",
    "        self.max_epsilon = max_epsilon\n",
    "        self.min_epsilon = min_epsilon\n",
    "        self.target_update = target_update\n",
    "        self.gamma = gamma\n",
    "        \n",
    "        # memory for 1-step Learning\n",
    "        self.memory = ReplayBuffer(\n",
    "            obs_dim, memory_size, batch_size, n_step=1\n",
    "        )\n",
    "        \n",
    "        # memory for N-step Learning\n",
    "        self.use_n_step = True if n_step > 1 else False\n",
    "        if self.use_n_step:\n",
    "            self.n_step = n_step\n",
    "            self.memory_n = ReplayBuffer(\n",
    "                obs_dim, memory_size, batch_size, n_step=n_step, gamma=gamma\n",
    "            )\n",
    "        \n",
    "        # device: cpu / gpu\n",
    "        self.device = torch.device(\n",
    "            \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
    "        )\n",
    "        print(self.device)\n",
    "\n",
    "        # networks: dqn, dqn_target\n",
    "        self.dqn = Network(obs_dim, action_dim).to(self.device)\n",
    "        self.dqn_target = Network(obs_dim, action_dim).to(self.device)\n",
    "        self.dqn_target.load_state_dict(self.dqn.state_dict())\n",
    "        self.dqn_target.eval()\n",
    "        \n",
    "        # optimizer\n",
    "        self.optimizer = optim.Adam(self.dqn.parameters())\n",
    "\n",
    "        # transition to store in memory\n",
    "        self.transition = list()\n",
    "        \n",
    "        # mode: train / test\n",
    "        self.is_test = False\n",
    "\n",
    "    def select_action(self, state: np.ndarray) -> np.ndarray:\n",
    "        \"\"\"Select an action from the input state.\"\"\"\n",
    "        # epsilon greedy policy\n",
    "        if self.epsilon > np.random.random():\n",
    "            selected_action = self.env.action_space.sample()\n",
    "        else:\n",
    "            selected_action = self.dqn(\n",
    "                torch.FloatTensor(state).to(self.device)\n",
    "            ).argmax()\n",
    "            selected_action = selected_action.detach().cpu().numpy()\n",
    "        \n",
    "        if not self.is_test:\n",
    "            self.transition = [state, selected_action]\n",
    "        \n",
    "        return selected_action\n",
    "\n",
    "    def step(self, action: np.ndarray) -> Tuple[np.ndarray, np.float64, bool]:\n",
    "        \"\"\"Take an action and return the response of the env.\"\"\"\n",
    "        next_state, reward, done, _ = self.env.step(action)\n",
    "\n",
    "        if not self.is_test:\n",
    "            self.transition += [reward, next_state, done]\n",
    "            \n",
    "            # N-step transition\n",
    "            if self.use_n_step:\n",
    "                one_step_transition = self.memory_n.store(*self.transition)\n",
    "            # 1-step transition\n",
    "            else:\n",
    "                one_step_transition = self.transition\n",
    "\n",
    "            # add a single step transition\n",
    "            if one_step_transition:\n",
    "                self.memory.store(*one_step_transition)\n",
    "    \n",
    "        return next_state, reward, done\n",
    "\n",
    "    def update_model(self) -> torch.Tensor:\n",
    "        \"\"\"Update the model by gradient descent.\"\"\"\n",
    "        samples = self.memory.sample_batch()\n",
    "        indices = samples[\"indices\"]\n",
    "        loss = self._compute_dqn_loss(samples, self.gamma)\n",
    "        \n",
    "        # N-step Learning loss\n",
    "        # we are gonna combine 1-step loss and n-step loss so as to\n",
    "        # prevent high-variance.\n",
    "        if self.use_n_step:\n",
    "            samples = self.memory_n.sample_batch_from_idxs(indices)\n",
    "            gamma = self.gamma ** self.n_step\n",
    "            n_loss = self._compute_dqn_loss(samples, gamma)\n",
    "            loss += n_loss\n",
    "\n",
    "        self.optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        self.optimizer.step()\n",
    "\n",
    "        return loss.item()\n",
    "        \n",
    "    def train(self, num_frames: int, plotting_interval: int = 200):\n",
    "        \"\"\"Train the agent.\"\"\"\n",
    "        self.is_test = False\n",
    "        \n",
    "        state = self.env.reset()\n",
    "        update_cnt = 0\n",
    "        epsilons = []\n",
    "        losses = []\n",
    "        scores = []\n",
    "        score = 0\n",
    "\n",
    "        for frame_idx in range(1, num_frames + 1):\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "\n",
    "            # if episode ends\n",
    "            if done:\n",
    "                state = self.env.reset()\n",
    "                scores.append(score)\n",
    "                score = 0\n",
    "\n",
    "            # if training is ready\n",
    "            if len(self.memory) >= self.batch_size:\n",
    "                loss = self.update_model()\n",
    "                losses.append(loss)\n",
    "                update_cnt += 1\n",
    "                \n",
    "                # linearly decrease epsilon\n",
    "                self.epsilon = max(\n",
    "                    self.min_epsilon, self.epsilon - (\n",
    "                        self.max_epsilon - self.min_epsilon\n",
    "                    ) * self.epsilon_decay\n",
    "                )\n",
    "                epsilons.append(self.epsilon)\n",
    "                \n",
    "                # if hard update is needed\n",
    "                if update_cnt % self.target_update == 0:\n",
    "                    self._target_hard_update()\n",
    "\n",
    "            # plotting\n",
    "            if frame_idx % plotting_interval == 0:\n",
    "                self._plot(frame_idx, scores, losses, epsilons)\n",
    "                \n",
    "        self.env.close()\n",
    "                \n",
    "    def test(self) -> List[np.ndarray]:\n",
    "        \"\"\"Test the agent.\"\"\"\n",
    "        self.is_test = True\n",
    "        \n",
    "        state = self.env.reset()\n",
    "        done = False\n",
    "        score = 0\n",
    "        \n",
    "        frames = []\n",
    "        while not done:\n",
    "            frames.append(self.env.render(mode=\"rgb_array\"))\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "        \n",
    "        print(\"score: \", score)\n",
    "        self.env.close()\n",
    "        \n",
    "        return frames\n",
    "    \n",
    "    def _compute_dqn_loss(\n",
    "        self, \n",
    "        samples: Dict[str, np.ndarray], \n",
    "        gamma: float\n",
    "    ) -> torch.Tensor:\n",
    "        \"\"\"Return dqn loss.\"\"\"\n",
    "        device = self.device  # for shortening the following lines\n",
    "        state = torch.FloatTensor(samples[\"obs\"]).to(device)\n",
    "        next_state = torch.FloatTensor(samples[\"next_obs\"]).to(device)\n",
    "        action = torch.LongTensor(samples[\"acts\"].reshape(-1, 1)).to(device)\n",
    "        reward = torch.FloatTensor(samples[\"rews\"].reshape(-1, 1)).to(device)\n",
    "        done = torch.FloatTensor(samples[\"done\"].reshape(-1, 1)).to(device)\n",
    "\n",
    "        # G_t   = r + gamma * v(s_{t+1})  if state != Terminal\n",
    "        #       = r                       otherwise\n",
    "        curr_q_value = self.dqn(state).gather(1, action)\n",
    "        next_q_value = self.dqn_target(next_state).max(\n",
    "            dim=1, keepdim=True\n",
    "        )[0].detach()\n",
    "        mask = 1 - done\n",
    "        target = (reward + gamma * next_q_value * mask).to(self.device)\n",
    "\n",
    "        # calculate dqn loss\n",
    "        loss = F.smooth_l1_loss(curr_q_value, target)\n",
    "\n",
    "        return loss\n",
    "\n",
    "    def _target_hard_update(self):\n",
    "        \"\"\"Hard update: target <- local.\"\"\"\n",
    "        self.dqn_target.load_state_dict(self.dqn.state_dict())\n",
    "                \n",
    "    def _plot(\n",
    "        self, \n",
    "        frame_idx: int, \n",
    "        scores: List[float], \n",
    "        losses: List[float], \n",
    "        epsilons: List[float],\n",
    "    ):\n",
    "        \"\"\"Plot the training progresses.\"\"\"\n",
    "        clear_output(True)\n",
    "        plt.figure(figsize=(20, 5))\n",
    "        plt.subplot(131)\n",
    "        plt.title('frame %s. score: %s' % (frame_idx, np.mean(scores[-10:])))\n",
    "        plt.plot(scores)\n",
    "        plt.subplot(132)\n",
    "        plt.title('loss')\n",
    "        plt.plot(losses)\n",
    "        plt.subplot(133)\n",
    "        plt.title('epsilons')\n",
    "        plt.plot(epsilons)\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Environment\n",
    "\n",
    "You can see the [code](https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py) and [configurations](https://github.com/openai/gym/blob/master/gym/envs/__init__.py#L53) of CartPole-v0 from OpenAI's repository."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# environment\n",
    "env_id = \"CartPole-v0\"\n",
    "env = gym.make(env_id)\n",
    "if IN_COLAB:\n",
    "    env = gym.wrappers.Monitor(env, \"videos\", force=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set random seed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[777]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "seed = 777\n",
    "\n",
    "def seed_torch(seed):\n",
    "    torch.manual_seed(seed)\n",
    "    if torch.backends.cudnn.enabled:\n",
    "        torch.backends.cudnn.benchmark = False\n",
    "        torch.backends.cudnn.deterministic = True\n",
    "\n",
    "np.random.seed(seed)\n",
    "seed_torch(seed)\n",
    "env.seed(seed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cpu\n"
     ]
    }
   ],
   "source": [
    "# parameters\n",
    "num_frames = 20000\n",
    "memory_size = 1000\n",
    "batch_size = 32\n",
    "target_update = 100\n",
    "epsilon_decay = 1 / 2000\n",
    "\n",
    "# train\n",
    "agent = DQNAgent(env, memory_size, batch_size, target_update, epsilon_decay)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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sv8QEREREVF7MYOIiIgaRimVE5FPArgL1pj765RSm0XkCgAblFK3AvgegB+IyE4Ax2EFkYiIiIiIqI0YICIiooZSSq0HsL5g22c9p1MA/qjV6yIiIiIiovJYYkZEREREREREtMgxQEREREREREREtMg1LUAkIheKyHYR2SkilzXrfoiIiIiIiIiIqD5NCRCJiA7gGwDeDuBMAB8QkTObcV9ERERERERERFSfZmUQnQtgp1Jqt1IqA+DHAC5u0n0REREREREREVEdmhUgGgKw33N+xN5GREREREREREQB07Ym1SJyiYhsEJENR44cadcyiIiIiIiIiIgWPVFKNf5GRc4HcLlS6m32+b8DAKXUF8rsfwTAvhrvbhmAozVetxW4vvoEeX1BXhvA9dUrSOs7RSm1vN2LaKcu/JwI4pqAYK4riGsCgrkursm/IK6r1jUt+s8IgJ8TLRTEdXFN/gVxXUFcExDMdTX9c6JZAaIQgB0A3gxgFMBjAP5EKbW5Cfe1QSm1rtG32yhcX32CvL4grw3g+uoV9PWRf0F8LoO4JiCY6wrimoBgrotr8i+I6wrimhaLID72QVwTEMx1cU3+BXFdQVwTEMx1tWJNoWbcqFIqJyKfBHAXAB3Adc0IDhERERERERERUf2aEiACAKXUegDrm3X7RERERERERETUGG1rUt1A17Z7ARVwffUJ8vqCvDaA66tX0NdH/gXxuQzimoBgriuIawKCuS6uyb8griuIa1osgvjYB3FNQDDXxTX5F8R1BXFNQDDX1fQ1NaUHERERERERERERdY5uyCAiIiIiIiIiIqI6dHSASEQuFJHtIrJTRC5r81pWici9IrJFRDaLyF/Z25eKyN0i8qz9c7DN69RF5EkRuc0+/zwRedR+DH8iIpE2ri0hIj8TkW0islVEzg/S4ycif20/t5tE5Eci0tPOx09ErhORwyKyybOt5OMllv+w17lRRM5p0/q+bD+/G0XkFhFJeC77O3t920Xkba1em+eyT4uIEpFl9vmWP3bUOK38nFjgc+ByERkVkafsfxd5rlPy976R6xaRvSLyjH3fG+xtVb9XiMiH7P2fFZEP1bGeMzyPxVMiMiUin2rH49So99Fyj42IrLUf+532daXGNZV87xSRNSIy53nMvl3pvsv9/2pcV8OeM6nh87TMmn7iWc9eEXmqlY+VVPl9sFW/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\n",
      "text/plain": [
       "<Figure size 1440x360 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "agent.train(num_frames)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test\n",
    "\n",
    "Run the trained agent (1 episode)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score:  200.0\n"
     ]
    }
   ],
   "source": [
    "frames = agent.test()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Render"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Define the Animation class */\n",
       "  function Animation(frames, img_id, slider_id, interval, loop_select_id){\n",
       "    this.img_id = img_id;\n",
       "    this.slider_id = slider_id;\n",
       "    this.loop_select_id = loop_select_id;\n",
       "    this.interval = interval;\n",
       "    this.current_frame = 0;\n",
       "    this.direction = 0;\n",
       "    this.timer = null;\n",
       "    this.frames = new Array(frames.length);\n",
       "\n",
       "    for (var i=0; i<frames.length; i++)\n",
       "    {\n",
       "     this.frames[i] = new Image();\n",
       "     this.frames[i].src = frames[i];\n",
       "    }\n",
       "    document.getElementById(this.slider_id).max = this.frames.length - 1;\n",
       "    this.set_frame(this.current_frame);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.get_loop_state = function(){\n",
       "    var button_group = document[this.loop_select_id].state;\n",
       "    for (var i = 0; i < button_group.length; i++) {\n",
       "        var button = button_group[i];\n",
       "        if (button.checked) {\n",
       "            return button.value;\n",
       "        }\n",
       "    }\n",
       "    return undefined;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.set_frame = function(frame){\n",
       "    this.current_frame = frame;\n",
       "    document.getElementById(this.img_id).src = this.frames[this.current_frame].src;\n",
       "    document.getElementById(this.slider_id).value = this.current_frame;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.next_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.previous_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.max(0, this.current_frame - 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.first_frame = function()\n",
       "  {\n",
       "    this.set_frame(0);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.last_frame = function()\n",
       "  {\n",
       "    this.set_frame(this.frames.length - 1);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.slower = function()\n",
       "  {\n",
       "    this.interval /= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.faster = function()\n",
       "  {\n",
       "    this.interval *= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_forward = function()\n",
       "  {\n",
       "    this.current_frame += 1;\n",
       "    if(this.current_frame < this.frames.length){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.first_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.last_frame();\n",
       "        this.reverse_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.last_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_reverse = function()\n",
       "  {\n",
       "    this.current_frame -= 1;\n",
       "    if(this.current_frame >= 0){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.last_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.first_frame();\n",
       "        this.play_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.first_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.pause_animation = function()\n",
       "  {\n",
       "    this.direction = 0;\n",
       "    if (this.timer){\n",
       "      clearInterval(this.timer);\n",
       "      this.timer = null;\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.play_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = 1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function(){t.anim_step_forward();}, this.interval);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.reverse_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = -1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function(){t.anim_step_reverse();}, this.interval);\n",
       "  }\n",
       "</script>\n",
       "\n",
       "<div class=\"animation\" align=\"center\">\n",
       "    <img id=\"_anim_imgKBOIBTOYBVOJJZON\">\n",
       "    <br>\n",
       "    <input id=\"_anim_sliderKBOIBTOYBVOJJZON\" type=\"range\" style=\"width:350px\" name=\"points\" min=\"0\" max=\"1\" step=\"1\" value=\"0\" onchange=\"animKBOIBTOYBVOJJZON.set_frame(parseInt(this.value));\"></input>\n",
       "    <br>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.slower()\">&#8211;</button>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.first_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.previous_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.reverse_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.pause_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.play_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.next_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.last_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKBOIBTOYBVOJJZON.faster()\">+</button>\n",
       "  <form action=\"#n\" name=\"_anim_loop_selectKBOIBTOYBVOJJZON\" class=\"anim_control\">\n",
       "    <input type=\"radio\" name=\"state\" value=\"once\" > Once </input>\n",
       "    <input type=\"radio\" name=\"state\" value=\"loop\" checked> Loop </input>\n",
       "    <input type=\"radio\" name=\"state\" value=\"reflect\" > Reflect </input>\n",
       "  </form>\n",
       "</div>\n",
       "\n",
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Instantiate the Animation class. */\n",
       "  /* The IDs given should match those used in the template above. */\n",
       "  (function() {\n",
       "    var img_id = \"_anim_imgKBOIBTOYBVOJJZON\";\n",
       "    var slider_id = \"_anim_sliderKBOIBTOYBVOJJZON\";\n",
       "    var loop_select_id = \"_anim_loop_selectKBOIBTOYBVOJJZON\";\n",
       "    var frames = new Array(0);\n",
       "    \n",
       "  frames[0] = \"\"\n",
       "  frames[1] = \"\"\n",
       "  frames[2] = \"\"\n",
       "  frames[3] = \"\"\n",
       "  frames[4] = \"\"\n",
       "  frames[5] = \"\"\n",
       "  frames[6] = \"\"\n",
       "  frames[7] = \"\"\n",
       "  frames[8] = \"\"\n",
       "  frames[9] = \"\"\n",
       "  frames[10] = \"\"\n",
       "  frames[11] = \"\"\n",
       "  frames[12] = \"\"\n",
       "  frames[13] = \"\"\n",
       "  frames[14] = \"\"\n",
       "  frames[15] = \"\"\n",
       "  frames[16] = \"\"\n",
       "  frames[17] = \"\"\n",
       "  frames[18] = \"\"\n",
       "  frames[19] = \"\"\n",
       "  frames[20] = \"\"\n",
       "  frames[21] = \"\"\n",
       "  frames[22] = \"\"\n",
       "  frames[23] = \"\"\n",
       "  frames[24] = \"\"\n",
       "  frames[25] = \"\"\n",
       "  frames[26] = \"\"\n",
       "  frames[27] = \"\"\n",
       "  frames[28] = \"\"\n",
       "  frames[29] = \"\"\n",
       "  frames[30] = \"\"\n",
       "  frames[31] = \"\"\n",
       "  frames[32] = \"\"\n",
       "  frames[33] = \"\"\n",
       "  frames[34] = \"\"\n",
       "  frames[35] = \"\"\n",
       "  frames[36] = \"\"\n",
       "  frames[37] = \"\"\n",
       "  frames[38] = \"\"\n",
       "  frames[39] = \"\"\n",
       "  frames[40] = \"\"\n",
       "  frames[41] = \"\"\n",
       "  frames[42] = \"\"\n",
       "  frames[43] = \"\"\n",
       "  frames[44] = \"\"\n",
       "  frames[45] = \"\"\n",
       "  frames[46] = \"\"\n",
       "  frames[47] = \"\"\n",
       "  frames[48] = \"\"\n",
       "  frames[49] = \"\"\n",
       "  frames[50] = \"\"\n",
       "  frames[51] = \"\"\n",
       "  frames[52] = \"\"\n",
       "  frames[53] = \"\"\n",
       "  frames[54] = \"\"\n",
       "  frames[55] = \"\"\n",
       "  frames[56] = \"\"\n",
       "  frames[57] = \"\"\n",
       "  frames[58] = \"\"\n",
       "  frames[59] = \"\"\n",
       "  frames[60] = \"\"\n",
       "  frames[61] = \"\"\n",
       "  frames[62] = \"\"\n",
       "  frames[63] = \"\"\n",
       "  frames[64] = \"\"\n",
       "  frames[65] = \"\"\n",
       "  frames[66] = \"\"\n",
       "  frames[67] = \"\"\n",
       "  frames[68] = \"\"\n",
       "  frames[69] = \"\"\n",
       "  frames[70] = \"\"\n",
       "  frames[71] = \"\"\n",
       "  frames[72] = \"\"\n",
       "  frames[73] = \"\"\n",
       "  frames[74] = \"\"\n",
       "  frames[75] = \"\"\n",
       "  frames[76] = \"\"\n",
       "  frames[77] = \"\"\n",
       "  frames[78] = \"\"\n",
       "  frames[79] = \"\"\n",
       "  frames[80] = \"\"\n",
       "  frames[81] = \"\"\n",
       "  frames[82] = \"\"\n",
       "  frames[83] = \"\"\n",
       "  frames[84] = \"\"\n",
       "  frames[85] = \"\"\n",
       "  frames[86] = \"\"\n",
       "  frames[87] = \"\"\n",
       "  frames[88] = \"\"\n",
       "  frames[89] = \"\"\n",
       "  frames[90] = \"\"\n",
       "  frames[91] = \"\"\n",
       "  frames[92] = \"\"\n",
       "  frames[93] = \"\"\n",
       "  frames[94] = \"\"\n",
       "  frames[95] = \"\"\n",
       "  frames[96] = \"\"\n",
       "  frames[97] = \"\"\n",
       "  frames[98] = \"\"\n",
       "  frames[99] = \"\"\n",
       "  frames[100] = \"\"\n",
       "  frames[101] = \"\"\n",
       "  frames[102] = \"\"\n",
       "  frames[103] = \"\"\n",
       "  frames[104] = \"\"\n",
       "  frames[105] = \"\"\n",
       "  frames[106] = \"\"\n",
       "  frames[107] = \"\"\n",
       "  frames[108] = \"\"\n",
       "  frames[109] = \"\"\n",
       "  frames[110] = \"\"\n",
       "  frames[111] = \"\"\n",
       "  frames[112] = \"\"\n",
       "  frames[113] = \"\"\n",
       "  frames[114] = \"\"\n",
       "  frames[115] = \"\"\n",
       "  frames[116] = \"\"\n",
       "  frames[117] = \"\"\n",
       "  frames[118] = \"\"\n",
       "  frames[119] = \"\"\n",
       "  frames[120] = \"\"\n",
       "  frames[121] = \"\"\n",
       "  frames[122] = \"\"\n",
       "  frames[123] = \"\"\n",
       "  frames[124] = \"\"\n",
       "  frames[125] = \"\"\n",
       "  frames[126] = \"\"\n",
       "  frames[127] = \"\"\n",
       "  frames[128] = \"\"\n",
       "  frames[129] = \"\"\n",
       "  frames[130] = \"\"\n",
       "  frames[131] = \"\"\n",
       "  frames[132] = \"\"\n",
       "  frames[133] = \"\"\n",
       "  frames[134] = \"\"\n",
       "  frames[135] = \"\"\n",
       "  frames[136] = \"\"\n",
       "  frames[137] = \"\"\n",
       "  frames[138] = \"\"\n",
       "  frames[139] = \"\"\n",
       "  frames[140] = \"\"\n",
       "  frames[141] = \"\"\n",
       "  frames[142] = \"\"\n",
       "  frames[143] = \"\"\n",
       "  frames[144] = \"\"\n",
       "  frames[145] = \"\"\n",
       "  frames[146] = \"\"\n",
       "  frames[147] = \"\"\n",
       "  frames[148] = \"\"\n",
       "  frames[149] = \"\"\n",
       "  frames[150] = \"\"\n",
       "  frames[151] = \"\"\n",
       "  frames[152] = \"\"\n",
       "  frames[153] = \"\"\n",
       "  frames[154] = \"\"\n",
       "  frames[155] = \"\"\n",
       "  frames[156] = \"\"\n",
       "  frames[157] = \"\"\n",
       "  frames[158] = \"\"\n",
       "  frames[159] = \"\"\n",
       "  frames[160] = \"\"\n",
       "  frames[161] = \"\"\n",
       "  frames[162] = \"\"\n",
       "  frames[163] = \"\"\n",
       "  frames[164] = \"\"\n",
       "  frames[165] = \"\"\n",
       "  frames[166] = \"\"\n",
       "  frames[167] = \"\"\n",
       "  frames[168] = \"\"\n",
       "  frames[169] = \"\"\n",
       "  frames[170] = \"\"\n",
       "  frames[171] = \"\"\n",
       "  frames[172] = \"\"\n",
       "  frames[173] = \"\"\n",
       "  frames[174] = \"\"\n",
       "  frames[175] = \"\"\n",
       "  frames[176] = \"\"\n",
       "  frames[177] = \"\"\n",
       "  frames[178] = \"\"\n",
       "  frames[179] = \"\"\n",
       "  frames[180] = \"\"\n",
       "  frames[181] = \"\"\n",
       "  frames[182] = \"\"\n",
       "  frames[183] = \"\"\n",
       "  frames[184] = \"\"\n",
       "  frames[185] = \"\"\n",
       "  frames[186] = \"\"\n",
       "  frames[187] = \"\"\n",
       "  frames[188] = \"\"\n",
       "  frames[189] = \"\"\n",
       "  frames[190] = \"\"\n",
       "  frames[191] = \"\"\n",
       "  frames[192] = \"\"\n",
       "  frames[193] = \"\"\n",
       "  frames[194] = \"\"\n",
       "  frames[195] = \"\"\n",
       "  frames[196] = \"\"\n",
       "  frames[197] = \"\"\n",
       "  frames[198] = \"\"\n",
       "  frames[199] = \"\"\n",
       "\n",
       "\n",
       "    /* set a timeout to make sure all the above elements are created before\n",
       "       the object is initialized. */\n",
       "    setTimeout(function() {\n",
       "        animKBOIBTOYBVOJJZON = new Animation(frames, img_id, slider_id, 50, loop_select_id);\n",
       "    }, 0);\n",
       "  })()\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "if IN_COLAB:  # for colab\n",
    "    import base64\n",
    "    import glob\n",
    "    import io\n",
    "    import os\n",
    "\n",
    "    from IPython.display import HTML, display\n",
    "\n",
    "\n",
    "    def ipython_show_video(path: str) -> None:\n",
    "        \"\"\"Show a video at `path` within IPython Notebook.\"\"\"\n",
    "        if not os.path.isfile(path):\n",
    "            raise NameError(\"Cannot access: {}\".format(path))\n",
    "\n",
    "        video = io.open(path, \"r+b\").read()\n",
    "        encoded = base64.b64encode(video)\n",
    "\n",
    "        display(HTML(\n",
    "            data=\"\"\"\n",
    "            <video alt=\"test\" controls>\n",
    "            <source src=\"data:video/mp4;base64,{0}\" type=\"video/mp4\"/>\n",
    "            </video>\n",
    "            \"\"\".format(encoded.decode(\"ascii\"))\n",
    "        ))\n",
    "\n",
    "    list_of_files = glob.glob(\"videos/*.mp4\")\n",
    "    latest_file = max(list_of_files, key=os.path.getctime)\n",
    "    print(latest_file)\n",
    "    ipython_show_video(latest_file)\n",
    "    \n",
    "else:  # for jupyter\n",
    "    from matplotlib import animation\n",
    "    from JSAnimation.IPython_display import display_animation\n",
    "    from IPython.display import display\n",
    "\n",
    "\n",
    "    def display_frames_as_gif(frames: List[np.ndarray]) -> None:\n",
    "        \"\"\"Displays a list of frames as a gif, with controls.\"\"\"\n",
    "        patch = plt.imshow(frames[0])\n",
    "        plt.axis('off')\n",
    "\n",
    "        def animate(i):\n",
    "            patch.set_data(frames[i])\n",
    "\n",
    "        anim = animation.FuncAnimation(\n",
    "            plt.gcf(), animate, frames = len(frames), interval=50\n",
    "        )\n",
    "        display(display_animation(anim, default_mode='loop'))\n",
    "\n",
    "\n",
    "    # display \n",
    "    display_frames_as_gif(frames)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
